import { Camera, Canvas, Node, Prefab } from 'cc';
import { DEBUG, DEV } from 'cc/env';
import { BaseGlobal, BaseModule, getGlobalType, getModuleType } from './base/BaseModule';
import * as debug from './lib/Debug';
import { loader } from './lib/Loader';
import { logger } from './lib/Logger';
import { storage } from './lib/Storage';
import { task } from './lib/Task';
import { AppGlobalUtility, AppModuleUtility } from './utillity/Utillity';

interface Action<T = void> {
    (result: T): void;
}

class App {
    public configuration = new class Configuration {
        Canvas: Canvas;
        Camera: Camera;
        UserInterface: Node;
        UIShadow: Prefab;
        UILoading: Prefab;
        UIToast: Prefab;
    };

    public lib = { task, storage, debug, logger, loader };

    // ### Global ###
    private _global: BaseGlobal;
    public get global(): BaseGlobal {
        return this._global;
    }

    public loadGlobal(onCompleted: Action<BaseGlobal> = null, onProgress: Action<number> = null) {
        if (this._global != null) {
            // 保证一定是异步的
            setTimeout(() => {
                onCompleted?.(this._global);
            });
        }
        else {
            const asmName = AppGlobalUtility.getAssemblyName();
            app.lib.loader.loadBundle({
                bundle: asmName,
                onComplete: (bundle) => {
                    if (bundle) {
                        const type = getGlobalType();
                        this._global = new type() as BaseGlobal;
                        BaseGlobal.load(this._global, onCompleted, onProgress);
                    } else {
                        console.error(`程序集加载失败: ${asmName}`);
                        onCompleted?.(null);
                    }
                },
            });
        }
    }

    public unloadGlobal() {
        BaseGlobal.unload(this._global);
        this._global = null;
    }
    // ###END###

    // ### Module ###
    private readonly _moduleCacheMap = new Map<string, BaseModule>();

    public loadModule(name: string, onCompleted: Action = null, onProgress: Action<number> = null) {
        if (this._moduleCacheMap.has(name)) {
            // 保证一定是异步的
            setTimeout(() => {
                onCompleted?.();
            });
        }
        else {
            const asmName = AppModuleUtility.getAssemblyName(name);
            const typeName = AppModuleUtility.getModuleTypeName(name);
            app.lib.loader.loadBundle({
                bundle: asmName,
                onComplete: (bundle) => {
                    if (bundle) {
                        const type = getModuleType(typeName);
                        const module = new type();
                        this._moduleCacheMap.set(name, module);
                        BaseModule.load(module, onCompleted, onProgress);
                    } else {
                        console.error(`程序集加载失败: ${asmName}`);
                        onCompleted?.();
                    }
                },
            });
        }
    }

    /**
     * 获取Module实例
     * @param type Module类(一定不要使用其它Bundle中的类)
     */
    public getModule(type: typeof BaseModule): BaseModule {
        if (this._moduleCacheMap.has(type.moduleName)) {
            return this._moduleCacheMap.get(type.moduleName);
        }
        return null;
    }

    public unloadModule(name: string) {
        if (this._moduleCacheMap.has(name)) {
            let module = this._moduleCacheMap.get(name);
            this._moduleCacheMap.delete(name);
            BaseModule.unload(module);
        }
    }

    public unloadAllModules() {
        this._moduleCacheMap.forEach(module => {
            BaseModule.unload(module);
        });

        this._moduleCacheMap.clear();
    }
    // ###END###
}

export const app = new App();

if (DEV || DEBUG) {
    //@ts-ignore
    window['app'] = app;
}